/**
 * 
 */
package bpel;

import java.net.URL;
import java.util.Hashtable;
import java.util.LinkedList;

import org.dom4j.Document;

import wsdl.service.WSDLBinding;
import wsdl.service.WSDLPort;
import wsdl.service.WSDLPortType;
import wsdl.service.WSDLService;
import bpel.instructions.BPELInstruction;
import bpel.types.BPELType;
import bpel.variables.BPELVariable;
import bpel.variables.BPELVariableFactory;

/**
 * @author Maurice & Topia
 * 
 */
public class BPELProcess {

	private String name;
	private URL targetNamespace;

	private Hashtable<String, String> inputs;

	private LinkedList<BPELImport> imports;

	private Hashtable<String, WSDLService> services;
	private Hashtable<String, WSDLBinding> bindings;
	private Hashtable<String, WSDLPortType> portTypes;

	private Hashtable<String, BPELVariable> variables;
	private Hashtable<String, BPELType> types;

	private LinkedList<BPELInstruction> instructions;

	public BPELProcess() {
		inputs = new Hashtable<String, String>();

		imports = new LinkedList<BPELImport>();
		services = new Hashtable<String, WSDLService>();
		bindings = new Hashtable<String, WSDLBinding>();
		portTypes = new Hashtable<String, WSDLPortType>();

		variables = new Hashtable<String, BPELVariable>();
		types = new Hashtable<String, BPELType>();

		instructions = new LinkedList<BPELInstruction>();
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public URL getTargetNamespace() {
		return targetNamespace;
	}

	public void setTargetNamespace(URL targetNamespace) {
		this.targetNamespace = targetNamespace;
	}

	public void addImport(BPELImport i) {
		imports.add(i);
	}

	public void addType(String name, BPELType type) {
		types.put(name, type);
	}

	public BPELType getType(String name) {
		return types.get(name);
	}

	public void addService(String name, WSDLService service) {
		services.put(name, service);
	}

	public void addBinding(String name, WSDLBinding binding) {
		bindings.put(name, binding);
	}

	public void addPortType(String name, WSDLPortType portType) {
		portTypes.put(name, portType);
	}

	public void addVariable(String name, String type) {

		BPELType t = types.get(type);

		if (t != null) {
			this.variables.put(name, BPELVariableFactory.getInstance().createVariable(name, t, this));
		} else {
			System.err.println("(BPELProcess) Type " + type + " undefined");
		}
	}

	public BPELVariable getVariable(String var) {
		
		String cleanVar = var.replace("'", "");
		
		BPELVariable v = this.variables.get(cleanVar);
		
		if (v == null) {
			System.err.println("(BPELProcess) Unknown variable : " + cleanVar);
		}
		
		return v;
	}

	public String getValueOfInput(String input) {
		String i = inputs.get(input);

		if (i == null) {
			System.err.println("(BPELProcess) Unknown input : " + input);
		}

		return i;
	}

	public void addInstruction(BPELInstruction instruction) {
		this.instructions.add(instruction);
	}

	public Document execute(String XMLClientData) {
		System.out.println("Executing process " + name + " : ");
		
		loadInputsFrom(XMLClientData);

		for (BPELInstruction i : instructions) {
			i.execute(this);
		}

		return variables.get("output").getXMLDescription();
	}

	private void loadInputsFrom(String clientRequestFilename) {
		System.out.println("Loading inputs...");
		getVariable("input").parse(clientRequestFilename);
	}

	public URL getServiceURL(String portType) {

		for (String serviceName : services.keySet()) {
			for (String portName : services.get(serviceName).getPorts().keySet()) {
				WSDLPort port = services.get(serviceName).getPorts().get(portName);

				if (port.getName().contains(portType)) {
					return port.getAddress();
				}
			}
		}

		return null;
	}

	@Override
	public String toString() {

		String processStr = "";

		processStr += "******************************************************************\n";
		processStr += "*** Process : " + name + "@" + targetNamespace + "\n";
		processStr += "******************************************************************\n";

		processStr += "\n*** Imports\n\n";

		for (BPELImport i : imports) {
			processStr += i.toString() + "\n";
		}

		processStr += "\n*** Types\n\n";

		for (String t : types.keySet()) {
			processStr += types.get(t).toString() + "\n";
		}

		processStr += "\n*** Services\n\n";

		for (String t : services.keySet()) {
			processStr += "\n" + services.get(t).toString() + "\n";
		}

		processStr += "\n*** Bindings\n\n";

		for (String t : bindings.keySet()) {
			processStr += "\n" + bindings.get(t).toString() + "\n";
		}

		processStr += "\n*** Port types\n\n";

		for (String t : portTypes.keySet()) {
			processStr += "\n" + portTypes.get(t).toString() + "\n";
		}

		processStr += "\n*** Variables\n\n";

		for (String var : variables.keySet()) {
			processStr += variables.get(var).toString() + "\n";
		}

		processStr += "\n*** Instructions\n\n";

		for (BPELInstruction i : instructions) {
			processStr += i.toString() + "\n";
		}

		processStr += "******************************************************************\n";

		return processStr;
	}
}
